package com.tuyrt.hi.ui.recyclerview

import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.StaggeredGridLayoutManager
import com.tuyrt.hi.library.log.HiLog
import com.tuyrt.hi.ui.R
import com.tuyrt.hi.ui.item.HiAdapter

/**
 *
 */
open class HiRecyclerView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0,
) : RecyclerView(context, attrs, defStyleAttr) {

    private var loadMoreScrollListener: LoadMoreScrollListener? = null
    private var footerView: View? = null
    private var isLoadingMore: Boolean = false

    inner class LoadMoreScrollListener(val prefetchSize: Int, val callback: () -> Unit) : OnScrollListener() {

        //咱们这里的强转，因为前面 会有前置检查
        val hiAdapter = adapter as HiAdapter

        override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
            //需要根据当前的滑动状态  已决定要不要添加footer view ，要不执行上拉加载分页的动作

            if (isLoadingMore) return

            //咱们需要判断当前类表上 已经显示的 item的个数 ，如果列表上已显示的item的数量小于0
            val totalItemCount = hiAdapter.itemCount
            if (totalItemCount <= 0) return

            // 是否向上拖动状态：1正数 表示从底部向上拖动
            val canScrollVertically = recyclerView.canScrollVertically(1)

            // 最底部可见 item 角标
            val lastVisibleItem = findLastVisibleItem(recyclerView)
            val firstVisibleItem = findFirstVisibleItem(recyclerView)
            if (lastVisibleItem <= 0) return

            // 是否已经滑动到达最底部
            val arriveBottom = lastVisibleItem >= totalItemCount - 1 && firstVisibleItem > 0
            // 添加 footer的条件:
            // 1. 当前处于拖动状态
            // 2. 能从底部向上拖动 or 已经达到底部
            if (newState == RecyclerView.SCROLL_STATE_DRAGGING && (canScrollVertically || arriveBottom)) {
                addFooterView()
            }

            // 不能在 滑动停止了，才去添加footer view
            if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                return
            }

            // 预加载，就是 不需要等待滑动到最后一个item的时候，就触发下一页的加载动作
            val arrivePrefetchPosition = totalItemCount - lastVisibleItem <= prefetchSize
            if (!arrivePrefetchPosition) return

            isLoadingMore = true
            callback()
        }

        private fun addFooterView() {
            val footerView = getFooterView()
            // 有个坑: 在一些边界场景下，会出现多次添加的情况，所以添加之前先 remove -> hiAdapter.removeFooterView()

            // 主要是为了避免 removeFooterView 不及时，在边界场景下可能会出现：footerView还没从recyclerView上移除，但我们又调用了addFooterView
            // 造成重复添加的情况，此时会抛出 add view must call removeview from it parent first exception
            if (footerView.parent != null) {
                footerView.post { addFooterView() }
            } else {
                hiAdapter.addFooterView(footerView)
            }
        }

        private fun getFooterView(): View {
            if (footerView == null) {
                footerView = LayoutInflater.from(context).inflate(R.layout.layout_footer_loading, this@HiRecyclerView, false)
            }
            return footerView!!
        }

        private fun findLastVisibleItem(recyclerView: RecyclerView): Int {
            when (val layoutManager = recyclerView.layoutManager) {
                // GridLayoutManager is LinearLayoutManager
                is LinearLayoutManager -> {
                    return layoutManager.findLastVisibleItemPosition()
                }
                is StaggeredGridLayoutManager -> {
                    return layoutManager.findLastVisibleItemPositions(null)[0]
                }
            }
            return -1
        }

        private fun findFirstVisibleItem(recyclerView: RecyclerView): Int {
            when (val layoutManager = recyclerView.layoutManager) {
                // GridLayoutManager is LinearLayoutManager
                is LinearLayoutManager -> {
                    return layoutManager.findFirstVisibleItemPosition()
                }
                is StaggeredGridLayoutManager -> {
                    return layoutManager.findFirstVisibleItemPositions(null)[0]
                }
            }
            return -1
        }
    }

    fun enableLoadMore(prefetchSize: Int, callback: () -> Unit) {
        if (adapter !is HiAdapter) {
            HiLog.e("enableLoadMore must use HiAdapter")
            return
        }
        loadMoreScrollListener = LoadMoreScrollListener(prefetchSize, callback)
        addOnScrollListener(loadMoreScrollListener!!)
    }

    fun disableLoadMore() {
        if (adapter !is HiAdapter) {
            HiLog.e("disableLoadMore must use HiAdapter")
            return
        }

        val hiAdapter = adapter as HiAdapter
        footerView?.let {
            if (footerView!!.parent != null) {
                hiAdapter.removeFooterView(footerView!!)
            }
        }

        loadMoreScrollListener?.let {
            removeOnScrollListener(loadMoreScrollListener!!)
            loadMoreScrollListener = null
            footerView = null
            isLoadingMore = false
        }
    }

    fun isLoading(): Boolean {
        return isLoadingMore
    }

    fun loadFinished(success: Boolean) {
        if (adapter !is HiAdapter) {
            HiLog.e("loadFinished must use HiAdapter")
            return
        }

        isLoadingMore = false
        val hiAdapter = adapter as HiAdapter
        if (!success) {
            footerView?.let {
                if (footerView!!.parent != null) {
                    hiAdapter.removeFooterView(footerView!!)
                }
            }
        } else {
            // nothing to do
        }

    }
}